package com.xxx.rpc.server.handler;

import com.xxx.rpc.message.RpcRequestMessage;
import com.xxx.rpc.message.RpcResponseMessage;
import com.xxx.rpc.server.service.ServicesFactory;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * rpc框架：服务端处理客户端发送过来的请求handler
 */
@Slf4j
@ChannelHandler.Sharable
public class RpcRequestMessageHandler extends SimpleChannelInboundHandler<RpcRequestMessage> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequestMessage message) {
        // 构建rpc响应对象
        RpcResponseMessage response = new RpcResponseMessage();
        response.setSequenceId(message.getSequenceId());
        try {
            // 通过rpc接口全限定名获取实现类代理对象
            Object service = ServicesFactory.getService(Class.forName(message.getInterfaceName()));
            // rpc阶方法和参数类型
            Method method = service.getClass().getMethod(message.getMethodName(), message.getParameterTypes());
            // 调用具体的接口
            Object invoke = method.invoke(service, message.getParameterValue());
            // 设置rpc响应对象返回值
            response.setReturnValue(invoke);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = e.getCause().getMessage();
            response.setExceptionValue(new Exception("远程调用出错:" + msg));  // 防止消息过长，不能直接将异常堆栈信息全部发送给客户端
        }
        ctx.writeAndFlush(response);
    }

    // 模拟测试本地rpc服务
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 构建rpc请求消息对象
        RpcRequestMessage message = new RpcRequestMessage(
                1,
                "com.xxx.rpc.server.service.HelloService",
                "sayHello",
                String.class,
                new Class[]{String.class},
                new Object[]{"张三"}
        );
        // 拿到反射获取的rpc服务实例
        Object service = ServicesFactory.getService(Class.forName(message.getInterfaceName()));
        // 通过方法名称获取rpc服务方法对象
        Method method = service.getClass().getMethod(message.getMethodName(), message.getParameterTypes());
        // 通过反射调用rpc服务方法
        Object result = method.invoke(service, message.getParameterValue());
        System.out.println(result);
    }
}
